namespace Yaaf.Wp7.AdvancedExplorer.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.IO;
    using System.Threading;
    using System.Windows;
    using System.Windows.Threading;

    using Yaaf.Wp7.AdvancedExplorer.Resources;
    using Yaaf.Wp7.AdvancedExplorer.Uploading;
    using Yaaf.WP7.NativeAccess.IO;
    using Yaaf.WP7.NativeAccess.Provision;
    using Yaaf.WP7.NativeAccess.Registry;

    interface IPivotView
    {
        string Header { get; }
    }

    public class MainViewModel : INotifyPropertyChanged
    {
        public bool IsWorking
        {
            get
            {
                return ExplorerView.IsListing || isWorking || registryView.IsWorking;
            }
        }

        private string currentFilter;

        public string CurrentFilter
        {
            get
            {
                return this.currentFilter;
            }
            set
            {
                if (this.currentFilter != value)
                {
                    this.currentFilter = value;
                    this.NotifyPropertyChanged("CurrentFilter");
                }
            }
        }

        private bool isFiltering;

        public bool IsFiltering
        {
            get
            {
                return this.isFiltering;
            }
            set
            {
                var old = this.isFiltering;
                if (old != value)
                {
                    this.isFiltering = value;
                    if (!value)
                    {
                        CurrentFilter = null;
                    }

                    this.NotifyPropertyChanged("IsFiltering");
                }
            }
        }

        private ExplorerViewModel explorerView;

        public ExplorerViewModel ExplorerView
        {
            get
            {
                return this.explorerView;
            }
            set
            {
                var old = this.explorerView;
                if (old != null)
                {
                    old.PropertyChanged -= this.explorerView_PropertyChanged;
                }

                this.explorerView = value;
                this.explorerView.PropertyChanged += this.explorerView_PropertyChanged;
            }
        }


        
        void explorerView_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsListing")
            {
                this.NotifyPropertyChanged("IsWorking");
            }
        }

        public RegistryViewModel RegistryView
        {
            get
            {
                return this.registryView;
            }
            set
            {
                var old = this.registryView;
                if (old != null)
                {
                    old.PropertyChanged -= this.registryView_PropertyChanged;
                }

                this.registryView = value;
                this.registryView.PropertyChanged += this.registryView_PropertyChanged;
            }
        }

        private void registryView_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "IsWorking")
            {
                this.NotifyPropertyChanged("IsWorking");
            }
        }

        public MainViewModel()
        {
            Registry.Initialize();
            FileSystemAccess.Initialize();
            ProvisionXml.Initialize();

            ExplorerView = new ExplorerViewModel(this);

            RegistryView = new RegistryViewModel(this);
            this.currentFilter = "";

            RemoteConnection = new RemoteConnectionViewModel(this);

            Settings = Settings.Current.Copy();
            SwitchView(ExplorerView);
        }

        public RemoteConnectionViewModel RemoteConnection { get; private set; }

        
        public bool IsDataLoaded
        {
            get;
            private set;
        }



        public void SwitchView(object newView)
        {
            CurrentView = newView;
            IsFiltering = false;
            CurrentFilter = "";
        }



        public RegistryValue CurrentValueEditing { get; set; }


        /// <summary>
        /// Creates and adds a few ItemViewModel objects into the Items collection.
        /// </summary>
        public void LoadData()
        {
            if (App.Current != null && App.Current.RootVisual != null)
            {
                dispatcher = App.Current.RootVisual.Dispatcher;
            }

            ExplorerView.LoadData();
            RemoteConnection.LoadData();
            RegistryView.LoadData();

            var workingThread = new Thread(DoUploadWork);
            workingThread.Start();

            this.IsDataLoaded = true;
        }

        private Dispatcher dispatcher;
        
        private bool isWorking;

        private ITask currentWork;
        void DoUploadWork()
        {
            while (true)
            {
                if (currentWork == null)
                {
                    if (workItems.Count <= 0)
                    {
                        Thread.Sleep(200);
                        continue;
                    }

                    lock (workingSync)
                    {
                        currentWork = workItems.Dequeue();
                    }
                    currentWork.Finished += this.current_Finished;
                    currentWork.Error += this.current_Error;
                    try
                    {
                        currentWork.Start();
                        this.isWorking = true;
                        dispatcher.BeginInvoke(() => this.NotifyPropertyChanged("IsWorking"));
                    }
                    catch (ThreadAbortException)
                    {
                        lock (workingSync)
                        {
                            currentWork = null;
                        }
                        throw;
                    }
                    catch (UnauthorizedAccessException e)
                    {
                        // Ignore this file! 
                        lock (workingSync)
                        {
                            currentWork = null;
                        }
                        Console.WriteLine(AppResources.MainViewModel_DoUploadWork_Ignore_Error + e.Message);
                    }
                    catch (IOException e)
                    {
                        // Ignore this file! 
                        lock (workingSync)
                        {
                            currentWork = null;
                        }
                        Console.WriteLine(AppResources.MainViewModel_DoUploadWork_Ignore_Error + e.Message);
                    }
                    catch (Exception e)
                    {
                        lock (workingSync)
                        {
                            currentWork = null;
                        }
                        dispatcher.BeginInvoke(
                            () =>
                            { throw e; });
                    }
                }
                else
                {
                    Thread.Sleep(200);
                }
            }
        }

        Queue<ITask> workItems = new Queue<ITask>();

        private readonly object workingSync = new object();

        
        internal void AddTasks(ITask task)
        {
            lock (workingSync)
            {
                workItems.Enqueue(task);
            }
        }

        internal void Invoke(Action action)
        {
            if (dispatcher != null)
            {
                dispatcher.BeginInvoke(action);
            }
            else
            {
                action();
            }
        }

        void current_Error(object sender, TaskErrorEventArgs e)
        {
            currentWork = null;
            this.isWorking = false;

            Invoke(() =>
            {
                this.NotifyPropertyChanged("IsWorking");
                MessageBox.Show(e.Error.ToString(), "Error", MessageBoxButton.OK);
            });
        }

        void current_Finished(object sender, TaskFinishedEventArgs e)
        {
            this.isWorking = false;
            currentWork = null;

            Invoke(() => this.NotifyPropertyChanged("IsWorking"));
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        

        private RegistryViewModel registryView;

        public Settings Settings { get; private set; }

        private object currentView;

        public object CurrentView
        {
            get
            {
                return this.currentView;
            }
            set
            {
                this.currentView = value;
            }
        }
    }

    internal class EntryComparer : IComparer<FileEntryViewModel>
    {
        public int Compare(FileEntryViewModel x, FileEntryViewModel y)
        {
            if (x.Element is WP7.NativeAccess.IO.DirectoryInfo == y.Element is WP7.NativeAccess.IO.DirectoryInfo)
            {
                return x.Element.FullName.CompareTo(y.Element.FullName);
            }

            if (!(x.Element is WP7.NativeAccess.IO.DirectoryInfo))
            {
                return 1;
            }
            return -1;
        }
    }
}